﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using Stripe;
using DomainModel;
using Utils;
using WebUI.Models;
using WebUI.Utils;
using WebUI.Infrastructure;
using WebUI.HtmlHelpers;

namespace WebUI.Controllers
{
    public class CoController : BaseController
    {
        [HttpGet]
        public ActionResult Detail(int coID)
        {
            //todo: detail page for company
            return View(new BaseViewModel());
        }

        [HttpGet]
        public ActionResult AboutPosting()
        {
            return View(new BaseViewModel());
        }

        [HttpGet]
        //non-loggedin: create/edit job,  and loggedin: create/edit job
        public ActionResult JobPosting(string jobToken)
        {
            //if has account logged in, remove jobtoken cookie first
            if (IdentityWithoutUserName.IsCoLoggedIn)
            {
                base.DeleteCookie(ConstUtils.C_JobToken);
                return View(new JobPostingViewModel(jobToken));
            }
            else
            {
                return View(new JobPostingViewModel(GetCookieValue(ConstUtils.C_JobToken)));
            }
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult JobPosting(JobPostingViewModel model, string jobToken)
        {
            if (model.Job.ApplyViaEmail && string.IsNullOrEmpty(model.Job.ApplyEmail))
            {
                ModelState.AddModelError("Job.ApplyEmail", "The Email field is required");
            }
            else if (!model.Job.ApplyViaEmail && string.IsNullOrEmpty(model.Job.ApplyUrl))
            {
                ModelState.AddModelError("Job.ApplyUrl", "The Url field is required");
            }
            if (ModelState.IsValid)
            {
                Job newResult = null;
                //only need to check avatar, but we can insert/update co and job first
                //insert or update co and job
                if (IdentityWithoutUserName.IsCoLoggedIn)
                {
                    base.DeleteCookie(ConstUtils.C_JobToken);
                    //if logged in, update avatar first, if failed, we don't insert new job into db, if success, we insert job
                    //if no file selected, insert job
                    if (model.Avatar == null)
                    {
                        //if has jobToken, means job edit
                        if (!string.IsNullOrEmpty(jobToken))
                        {
                            int jobID = ViewModelUtils.GetJobIDFromToken(jobToken);
                            string jobGUID = ViewModelUtils.GetJobGUIDFromToken(jobToken);
                            newResult = DataUtils.UpdateJobAndUpdateCo(model.Co, model.Job, jobID, jobGUID, IdentityWithoutUserName.AccountID);
                        }
                        else
                        {
                            newResult = DataUtils.UpdateCoAndInsertJob(model.Co, model.Job, IdentityWithoutUserName.AccountID);
                        }
                        return RedirectToAction("JobPostingPreview", new { JobToken = newResult.JobToken});
                    }
                    else
                    {
                        //if has file selected, try  upload and update
                        UploadResult result = ImageUtils.UploadAvatar(model.Avatar, base.GetWebProjectPhysicalPath(), AvatarType.CoAvatar, IdentityWithoutUserName.AccountID);
                        if (result.Result == UploadResultEnum.Success)
                        {
                            //if has jobToken, means job edit
                            if (!string.IsNullOrEmpty(jobToken))
                            {
                                int jobID = ViewModelUtils.GetJobIDFromToken(jobToken);
                                string jobGUID = ViewModelUtils.GetJobGUIDFromToken(jobToken);
                                newResult = DataUtils.UpdateJobAndUpdateCo(model.Co, model.Job, jobID, jobGUID, IdentityWithoutUserName.AccountID);
                            }
                            else
                            {
                                newResult = DataUtils.UpdateCoAndInsertJob(model.Co, model.Job, IdentityWithoutUserName.AccountID);
                            }
                            return RedirectToAction("JobPostingPreview", new { JobToken = newResult.JobToken});
                        }
                        else
                        {
                            string errorMessage = ViewModelUtils.GetUploadErrorMessage(result.Result);
                            ModelState.AddModelError("Avatar", errorMessage);
                            model.SetPublicVarsAfterBindingDynamicParams();
                            return View(model);
                        }
                    }
                    
                }
                else
                {
                    string jobTokenFromCookie = GetCookieValue(ConstUtils.C_JobToken);
                    string jobGUID = ViewModelUtils.GetJobGUIDFromToken(jobTokenFromCookie);
                    int jobID = ViewModelUtils.GetJobIDFromToken(jobTokenFromCookie);

                    if (jobID <= 0 || string.IsNullOrEmpty(jobGUID))
                    {
                        newResult = DataUtils.InsertCoAndInsertJob(model.Co, model.Job);
                        //update successfully, write jobGUID and jobID into cookie
                        base.CreateCookie(ConstUtils.C_JobToken, newResult.JobToken, 7);
                        //not logged in, after post a job, remember to clear the cookie
                    }
                    else
                    {
                        //update job first and then update co
                        newResult = DataUtils.UpdateJobAndUpdateCo(model.Co, model.Job, jobID, jobGUID, 0);
                        //update success, but don't change cookie
                    }

                    //if coid > 0, then upload avatar and update
                    if (newResult.CoID > 0)
                    {
                        //if no file selected
                        if (model.Avatar == null)
                        {
                            //success
                            return RedirectToAction("JobPostingPreview");
                        }
                        else
                        {
                            //if has file selected, try  upload and update
                            UploadResult result = ImageUtils.UploadAvatar(model.Avatar, base.GetWebProjectPhysicalPath(), AvatarType.CoAvatar, newResult.CoID);
                            if (result.Result == UploadResultEnum.Success)
                            {
                                //success
                                return RedirectToAction("JobPostingPreview");
                            }
                            else
                            {
                                string errorMessage = ViewModelUtils.GetUploadErrorMessage(result.Result);
                                ModelState.AddModelError("Avatar", errorMessage);
                                model.SetPublicVarsAfterBindingDynamicParams();
                                return View(model);
                            }
                        }
                    }
                    else
                    {
                        //some error happen
                        CreateSessionMessageForError("some error occurs, please try it again");
                        model.SetPublicVarsAfterBindingDynamicParams();
                        return View(model);
                    }
                }
            }
            else
            {
                model.SetPublicVarsAfterBindingDynamicParams();
                return View(model);
            }
        }

        [HttpGet]
        public ActionResult JobPostingPreview(string jobToken)
        {
            //if not logged in as company, jobToken always from cookie, otherwise, it's from url parameters
            if (!IdentityWithoutUserName.IsCoLoggedIn)
            {
                jobToken = GetCookieValue(ConstUtils.C_JobToken);
            }
            return View(new JobPostingPreviewViewModel(jobToken));
        }

        [HttpGet]
        public ActionResult GoPayment(string jobToken)
        {
            //if not logged in as company, jobToken always from cookie, otherwise, it's from url parameters
            if (!IdentityWithoutUserName.IsCoLoggedIn)
            {
                jobToken = GetCookieValue(ConstUtils.C_JobToken);
                return View("GoPaymentForNonLoggedIn", new JobPayNonLoggedInViewModel(jobToken));
            }
            else
            { 
                //if logged in as company, check if has jobcredits
                int jobCredits = DataUtils.GetCoJobCredits(IdentityWithoutUserName.LoginID, IdentityWithoutUserName.AccountID);
                if (jobCredits > 0)
                {
                    return View("GoPaymentForLoggedInWithCredits", new JobPayLoggedInWithCreditsViewModel(jobToken));
                }
                else
                {
                    return View("GoPaymentForLoggedInWithoutCredits", new JobPayLoggedInWithoutCreditsViewModel(jobToken));
                }
            }
            
        }

        [HttpPost]
        [ValidateInput(false)]
        public JsonResult GoPaymentForNonLoggedIn(JobPayNonLoggedInViewModel model)
        {
            //since this function works for non-loggedIn or individual logged in cases,
            //so if come in here, and found some company account logged in, we just redirect to company/joblist and tell user what's going on
            if (base.IdentityWithoutUserName.IsCoLoggedIn)
            {
                var redirect = "/company/joblist";
                return Json(JsonResultModelHelper.ForError(redirect, "We can not create a company account and post the listing for you since you already logged in as a company account")); //return out of function
            }

            //check job and co ID from cookie, make sure they exists in tables
            //JobToken in cooke contains JobGUID-JobID pair
            string jobToken = GetCookieValue(ConstUtils.C_JobToken);
            string jobGUID = ViewModelUtils.GetJobGUIDFromToken(jobToken);
            int jobID = ViewModelUtils.GetJobIDFromToken(jobToken);
            int coID = 0;
            //for any case, just call this to get CoJob
            CoJob coJob = DataUtils.GetCoJobByJobTokenAndCoID(jobGUID, jobID, coID);
            if (coJob == null || coJob.Job == null || coJob.Co == null || coJob.Job.JobID <= 0 || coJob.Co.CoID <= 0)
            {
                return Json(JsonResultModelHelper.ForError("You have no job to pay. Please go to <a href='/job/post'>create a listing</a> first")); //return out of function
            }

            if (ModelState.IsValid)
            {
                //check userName
                //check if username, email exists in db
                int checkResult = SqlUtilities.Query<int>(ConstUtils.SP_CheckUserNameAndEmail, new { Email = model.Email, UserName = model.UserName }).Single();
                if (checkResult == 0)
                {
                    JobPackage selectedPackage = GlobalUtilities.GetInstance().JobPackageList.Find(x => x.JobPackageID == model.JobPackageID);
                    //check jobpackage
                    if (model.JobPackageID < 1 || model.JobPackageID > 7 || selectedPackage == null)
                    {
                        ModelState.AddModelError("JobPackageID", "You are picking invaild job package.");
                        return Json(JsonResultModelHelper.ForError(ModelState)); //return out of function
                    }
                    int jobCredits = selectedPackage.JobCredits - 1;
                    int amountInCents = selectedPackage.Total * 100;
                    string description = model.Email + ", " + selectedPackage.Name + " Job Package";
                    //try to charge first
                    StripeCard card = null;
                    try
                    {
                        var option = new StripeChargeCreateOptions();
                        option.TokenId = model.StripeToken;
                        option.AmountInCents = amountInCents;
                        option.Currency = "usd";
                        option.Description = description;
                        //create a charge based on stripeToken
                        var chargeService = new StripeChargeService();
                        StripeCharge charge = chargeService.Create(option);
                        //if charge.Paid != true, means not successful
                        if (charge == null || charge.Paid == null || !charge.Paid.Value)
                        {
                            return Json(JsonResultModelHelper.ForError("Sorry, we can't charge your card successfully. Please try it again or try another card.")); //return out of function
                        }
                        else
                        {
                            card = charge.StripeCard;
                        }
                        
                    }
                    catch(Exception e)
                    {
                        return Json(JsonResultModelHelper.ForError(e.Message)); //return out of function
                    }

                    string confirmationKey = CommonUtilities.CreateGUIDKey();
                    //insert a login and update co and job table
                    int loginID = SqlUtilities.Query<int>(ConstUtils.SP_InsertLoginAndUpdateCoAndJob,
                        new
                        {
                            Email = model.Email,
                            PasswordHash = PasswordHash.CreateHash(model.Password),
                            UserName = model.UserName,
                            EmailConfirmationKey = confirmationKey,
                            CoID = coJob.Co.CoID,
                            JobID = coJob.Job.JobID,
                            JobCredits = jobCredits
                        }, null, true).FirstOrDefault();
                    //insert BillingInfo 
                    SqlUtilities.Execute(ConstUtils.SP_InsertBillingInfo, new
                        {
                            LoginID = loginID,
                            TransType = "Job Package " + selectedPackage.JobPackageID,
                            TransAmount = selectedPackage.Total,
                            Last4 = card.Last4,
                            CardType = card.Type,
                            StripeToken = model.StripeToken,
                            Country = card.Country, 
                            FingerPrint = card.Fingerprint,
                            CvcCheck = card.CvcCheck,
                            ExpirationMonth = card.ExpirationMonth,
                            ExpirationYear = card.ExpirationYear
                        }, null, true);
                    
                    try
                    {
                        //send email for signup
                        EmailUtils.Send(
                            GlobalUtilities.GetInstance().Email_NoReply,
                            model.Email,
                            EmailTemplateType.SignUp,
                            new string[] { model.UserName, model.Email, base.AbsoluteUrlForEmailConfirmation(model.Email, confirmationKey) },
                            loginID);
                    }
                    catch
                    { }

                    try
                    {
                        var emailDes = "Purchased " + selectedPackage.Name + " Job Package";
                        //send email for receipt 
                        EmailUtils.Send(
                            GlobalUtilities.GetInstance().Email_NoReply,
                            model.Email,
                            EmailTemplateType.JobPackagePayment,
                            new string[] { model.UserName, DateTime.Now.ToDateTimeString(), "US $" + selectedPackage.Total.ToString(), emailDes},
                            loginID);
                    }
                    catch { }

                    //remove jobtoken cookie 
                    base.DeleteCookie(ConstUtils.C_JobToken);

                    //set up the Auth cookie
                    string authCookieValue = loginID.ToString() + "|" + coJob.Co.CoID.ToString() + "|c";
                    FormsAuthentication.SetAuthCookie(authCookieValue, true);
                    //redirect to Account Profile
                    string redirectUrl = Url.Action("EditAccountProfile", "Account");
                    return Json(JsonResultModelHelper.ForSuccess(redirectUrl, "Your job listing has been published. The listing is editable in 3 days"));
                   
                }
                else
                {
                    if (checkResult == 1)
                    {
                        ModelState.AddModelError("Email", "This Email has been registered in our system.");
                    }
                    else if (checkResult == 2)
                    {
                        ModelState.AddModelError("UserName", "This User name has been taken in our system.");
                    }
                    else
                    {
                        ModelState.AddModelError("Email", "This Email has been registered in our system.");
                        ModelState.AddModelError("UserName", "This User name has been taken in our system.");
                    }

                    return Json(JsonResultModelHelper.ForError(ModelState));
                }
            }
            else
            {
                return Json(JsonResultModelHelper.ForError(ModelState));
            }
        }

        [HttpPost]
        [ValidateInput(false)]
        public JsonResult GoPaymentForLoggedInWithCredits(JobPayLoggedInWithCreditsViewModel model)
        {
            //for any case, just call this to get CoJob
            string jobGUID = ViewModelUtils.GetJobGUIDFromToken(model.JobToken);
            int jobID = ViewModelUtils.GetJobIDFromToken(model.JobToken);
            int coID = IdentityWithoutUserName.AccountID;
            CoJob coJob = DataUtils.GetCoJobByJobTokenAndCoID(jobGUID, jobID, coID);
            //make sure we can find the job
            if (coJob == null || coJob.Job == null || coJob.Co == null || coJob.Job.JobID <= 0 || coJob.Co.CoID <= 0)
            {
                return Json(JsonResultModelHelper.ForError("You have no job to pay. Please go to <a href='/job/post'>create a listing</a> first")); //return out of function
            }
            else
            { 
                //check jobcredits, make sure it's greater than 0
                if (coJob.Co.JobCredits > 0)
                {
                    //update jobcredits and job status
                    SqlUtilities.Execute(ConstUtils.SP_UpdateCoAndJob, new { coID, jobID }, null, true);
                    //redirect to Account Profile
                    string redirectUrl = Url.Action("JobList");
                    return Json(JsonResultModelHelper.ForSuccess(redirectUrl, "Publish the job listing successfully"));
                }
                else
                { 
                    //if no jobcredits, go to /job/pay and it will show credit card page
                    string redirectUrl = Url.Action("GoPayment", new {JobToken = model.JobToken});
                    return Json(JsonResultModelHelper.ForError(redirectUrl, "Sorry, you don't have job credits available. Please purchase job package and publish this listing"));
                }
            }
        }

        [HttpPost]
        [ValidateInput(false)]
        public JsonResult GoPaymentForLoggedInWithoutCredits(JobPayLoggedInWithoutCreditsViewModel model)
        {
            //for any case, just call this to get CoJob
            string jobGUID = ViewModelUtils.GetJobGUIDFromToken(model.JobToken);
            int jobID = ViewModelUtils.GetJobIDFromToken(model.JobToken);
            int coID = IdentityWithoutUserName.AccountID;
            CoJob coJob = DataUtils.GetCoJobByJobTokenAndCoID(jobGUID, jobID, coID);
            //make sure we can find the job
            if (coJob == null || coJob.Job == null || coJob.Co == null || coJob.Job.JobID <= 0 || coJob.Co.CoID <= 0)
            {
                return Json(JsonResultModelHelper.ForError("You have no job to pay. Please go to <a href='/job/post'>create a listing</a> first")); //return out of function
            }
            else
            {
                if (ModelState.IsValid)
                {
                    JobPackage selectedPackage = GlobalUtilities.GetInstance().JobPackageList.Find(x => x.JobPackageID == model.JobPackageID);
                    //check jobpackage
                    if (model.JobPackageID < 1 || model.JobPackageID > 7 || selectedPackage == null)
                    {
                        ModelState.AddModelError("JobPackageID", "You are picking invaild job package.");
                        return Json(JsonResultModelHelper.ForError(ModelState)); //return out of function
                    }
                    int jobCredits = selectedPackage.JobCredits - 1;
                    int amountInCents = selectedPackage.Total * 100;
                    string description = "LoginID: " + IdentityWithoutUserName.LoginID.ToString() + ", " + selectedPackage.Name + " Job Package";
                    //try to charge first
                    StripeCard card = null;
                    try
                    {
                        var option = new StripeChargeCreateOptions();
                        option.TokenId = model.StripeToken;
                        option.AmountInCents = amountInCents;
                        option.Currency = "usd";
                        option.Description = description;
                        //create a charge based on stripeToken
                        var chargeService = new StripeChargeService();
                        StripeCharge charge = chargeService.Create(option);
                        //if charge.Paid != true, means not successful
                        if (charge == null || charge.Paid == null || !charge.Paid.Value)
                        {
                            return Json(JsonResultModelHelper.ForError("Sorry, we can't charge your card successfully. Please try it again or try another card.")); //return out of function
                        }
                        else
                        {
                            card = charge.StripeCard;
                        }
                        //update job credits in co table
                        SqlUtilities.Execute(ConstUtils.SP_UpdateJobCreditsAndStatus, new { coID, jobID,  AddCredits = jobCredits }, null, true);
                        //insert BillingInfo 
                        SqlUtilities.Execute(ConstUtils.SP_InsertBillingInfo, new
                        {
                            LoginID = IdentityWithoutUserName.LoginID,
                            TransType = "Job Package " + selectedPackage.JobPackageID,
                            TransAmount = selectedPackage.Total,
                            Last4 = card.Last4,
                            CardType = card.Type,
                            StripeToken = model.StripeToken,
                            Country = card.Country,
                            FingerPrint = card.Fingerprint,
                            CvcCheck = card.CvcCheck,
                            ExpirationMonth = card.ExpirationMonth,
                            ExpirationYear = card.ExpirationYear
                        }, null, true);

                        try
                        {
                            Login login = DataUtils.GetLoginByID(IdentityWithoutUserName.LoginID);

                            var emailDes = "Purchased " + selectedPackage.Name + " Job Package";
                            //send email for receipt 
                            EmailUtils.Send(
                                GlobalUtilities.GetInstance().Email_NoReply,
                                login.Email,
                                EmailTemplateType.JobPackagePayment,
                                new string[] { login.UserName, DateTime.Now.ToDateTimeString(), "US $" + selectedPackage.Total.ToString(), emailDes },
                                IdentityWithoutUserName.LoginID);
                        }
                        catch { }

                        //redirect to Account Profile
                        string redirectUrl = Url.Action("JobList");
                        return Json(JsonResultModelHelper.ForSuccess(redirectUrl, "Publish the job listing successfully"));

                    }
                    catch (Exception e)
                    {
                        return Json(JsonResultModelHelper.ForError(e.Message)); //return out of function
                    }
                }
                else
                {
                    return Json(JsonResultModelHelper.ForError(ModelState));
                }
            }
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult BuyCredits()
        {
            return View(new BuyCreditsViewModel());
        }

        [Authorize(Roles = RoleNames.Company)]
        [HttpPost]
        [ValidateInput(false)]
        public JsonResult BuyCredits(BuyCreditsViewModel model)
        {
            if (ModelState.IsValid)
            {
                JobPackage selectedPackage = GlobalUtilities.GetInstance().JobPackageList.Find(x => x.JobPackageID == model.JobPackageID);
                //check jobpackage
                if (model.JobPackageID < 1 || model.JobPackageID > 7 || selectedPackage == null)
                {
                    ModelState.AddModelError("JobPackageID", "You are picking invaild job package.");
                    return Json(JsonResultModelHelper.ForError(ModelState)); //return out of function
                }
                int jobCredits = selectedPackage.JobCredits;
                int amountInCents = selectedPackage.Total * 100;
                string description = "LoginID: " + IdentityWithoutUserName.LoginID.ToString() + ", " + selectedPackage.Name + " Job Package";
                //try to charge first
                StripeCard card = null;
                try
                {
                    var option = new StripeChargeCreateOptions();
                    option.TokenId = model.StripeToken;
                    option.AmountInCents = amountInCents;
                    option.Currency = "usd";
                    option.Description = description;
                    //create a charge based on stripeToken
                    var chargeService = new StripeChargeService();
                    StripeCharge charge = chargeService.Create(option);
                    //if charge.Paid != true, means not successful
                    if (charge == null || charge.Paid == null || !charge.Paid.Value)
                    {
                        return Json(JsonResultModelHelper.ForError("Sorry, we can't charge your card successfully. Please try it again or try another card.")); //return out of function
                    }
                    else
                    {
                        card = charge.StripeCard;
                    }
                    //update job credits in co table
                    SqlUtilities.Execute(ConstUtils.SP_UpdateJobCredits, new { IdentityWithoutUserName.LoginID, CoID = IdentityWithoutUserName.AccountID, AddCredits = jobCredits }, null, true);
                    //insert BillingInfo 
                    SqlUtilities.Execute(ConstUtils.SP_InsertBillingInfo, new
                    {
                        LoginID = IdentityWithoutUserName.LoginID,
                        TransType = "Job Package " + selectedPackage.JobPackageID,
                        TransAmount = selectedPackage.Total,
                        Last4 = card.Last4,
                        CardType = card.Type,
                        StripeToken = model.StripeToken,
                        Country = card.Country,
                        FingerPrint = card.Fingerprint,
                        CvcCheck = card.CvcCheck,
                        ExpirationMonth = card.ExpirationMonth,
                        ExpirationYear = card.ExpirationYear
                    }, null, true);

                    try
                    {
                        Login login = DataUtils.GetLoginByID(IdentityWithoutUserName.LoginID);

                        var emailDes = "Purchased " + selectedPackage.Name + " Job Package";
                        //send email for receipt 
                        EmailUtils.Send(
                            GlobalUtilities.GetInstance().Email_NoReply,
                            login.Email,
                            EmailTemplateType.JobPackagePayment,
                            new string[] { login.UserName, DateTime.Now.ToDateTimeString(), "US $" + selectedPackage.Total.ToString(), emailDes },
                            IdentityWithoutUserName.LoginID);
                    }
                    catch { }

                    //redirect to Account Profile
                    string redirectUrl = Url.Action("JobList");
                    return Json(JsonResultModelHelper.ForSuccess(redirectUrl, "Thank you for purchasing job package."));
                   
                }
                catch (Exception e)
                {
                    return Json(JsonResultModelHelper.ForError(e.Message)); //return out of function
                }
            }
            else {
                return Json(JsonResultModelHelper.ForError(ModelState));
            }
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult SendEmailConfirmation()
        {
            CoLogin coLogin = DataUtils.GetCoLoginByID(IdentityWithoutUserName.LoginID);
            string newConfirmationKey = CommonUtilities.CreateGUIDKey();
            //update key in db first, 
            SqlUtilities.Execute(ConstUtils.SP_UpdateEmailConfirmationKey, new { LoginID = IdentityWithoutUserName.LoginID, Key = newConfirmationKey }, null, true);
            //then send email
            EmailUtils.Send(
                GlobalUtilities.GetInstance().Email_NoReply,
                coLogin.Login.Email,
                EmailTemplateType.SignUp,
                new string[]{
                    coLogin.Login.UserName,
                    coLogin.Login.Email,
                    AbsoluteUrlForEmailConfirmation(coLogin.Login.Email, newConfirmationKey)
                }, coLogin.Login.LoginID);
            return RedirectToAction("EditProfile");
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult EditProfile()
        {
            return View(new CoEditProfileViewModel());
        }

        [Authorize(Roles = RoleNames.Company)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditProfile(CoEditProfileViewModel model)
        {
            if (ModelState.IsValid)
            {
                //update login and co
                //check username unique
                //check if username, email exists in db, although now we don't allow user to change email, but we can keep code here
                int checkResult = SqlUtilities.Query<int>(ConstUtils.SP_CheckUserNameAndEmail, new { Email = model.Login.Email, UserName = model.Login.UserName, LoginID = IdentityWithoutUserName.LoginID }).Single();
                //passed, insert into db
                if (checkResult == 0)
                {
                    try
                    {
                        SqlUtilities.Execute(ConstUtils.SP_UpdateLoginAndCo, new
                        {
                            LoginID = IdentityWithoutUserName.LoginID,
                            UserName = model.Login.UserName,
                            
                            CoName = model.Co.Name,
                            CoTypeID = model.Co.CoTypeID,
                            CoUrl = model.Co.CoUrl,
                            CoDescription = model.Co.Description,
                            CoLocation = model.Co.Location
                        }, null, true);
                        base.CreateSessionMessageForSuccess("Your change has been updated");
                    }
                    catch
                    {
                        base.CreateSessionMessageForError("Sorry, internal error occurred. Please try it again.");
                    }
                }
                else if (checkResult == 1)
                {
                    ModelState.AddModelError("Login.Email", "This Email has been registered in our system.");
                }
                else if (checkResult == 2)
                {
                    ModelState.AddModelError("Login.UserName", "This User name has been taken in our system.");
                }
                else
                {
                    ModelState.AddModelError("Login.Email", "This Email has been registered in our system.");
                    ModelState.AddModelError("Login.UserName", "This User name has been taken in our system.");
                }

                return View(model);
            }
            else
            {
                return View(model);
            }
        }

        [Authorize(Roles = RoleNames.Company)]
        [HttpPost]
        public JsonResult EditAvatar(CoEditProfileViewModel model)
        {
            //check Avatar, validate file type, size etc
            if (ModelState.IsValid)
            {
                //upload file to disk, create differnt size thumbnail, extract image file info: width, height, insert into db 
                //update AvatarUrl in model
                UploadResult result = ImageUtils.UploadAvatar(model.Avatar, GetWebProjectPhysicalPath(), AvatarType.CoAvatar, IdentityWithoutUserName.AccountID);
                if (result.Result == UploadResultEnum.Success)
                {
                    return Json(
                        JsonResultUploadFileModelHelper.ForSuccessWithFilePathAndSummaryMessage(
                            Url.StaticFile(ImageUtils.GetAvatarRelativeUrl(AvatarType.CoAvatar, IdentityWithoutUserName.AccountID,
                                AvatarSizeEnum.Avatar_80x80, ImageUtils.GetImageFileExtension(model.Avatar))),
                            "Company profile picture has been updated"
                        )
                    );
                }
                else
                {
                    string message = ViewModelUtils.GetUploadErrorMessage(result.Result);
                    return Json(JsonResultUploadFileModelHelper.ForError(message));
                }
            }
            else
            {
                return Json(JsonResultUploadFileModelHelper.ForError("Some error occurs, please try it again."));
            }
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult EditPassword()
        {
            return View(new CoEditPasswordViewModel());
        }

        [Authorize(Roles = RoleNames.Company)]
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditPassword(CoEditPasswordViewModel model)
        {
            if (ModelState.IsValid)
            {
                //save new password to db
                try
                {
                    string goodHash = string.Empty;
                    Login login = DataUtils.GetLoginByID(IdentityWithoutUserName.LoginID);
                    if (login != null)
                    {
                        goodHash = login.PasswordHash;
                    }
                    if (PasswordHash.ValidatePassword(model.OldPassword, goodHash))
                    {
                        SqlUtilities.Execute(ConstUtils.SP_UpdatePassword,
                            new
                            {
                                LoginID = IdentityWithoutUserName.LoginID,
                                NewPasswordHash = PasswordHash.CreateHash(model.NewPassword)
                            },
                            null, true);
                        base.CreateSessionMessageForSuccess("Your password has been updated");
                    }
                    else
                    {
                        ModelState.AddModelError("OldPassword", "Old password is incorrect");
                    }

                }
                catch
                {
                    ModelState.AddModelError("", "Internal error occurs. Please try it again.");
                }

            }
            return View(model);
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult JobList(string t, int? page)
        {
            if (!string.IsNullOrEmpty(t))
            {
                t = t.ToLower();
            }
            if (!string.IsNullOrEmpty(t) && t != "active" && t != "unpublished" && t != "expired")
            {
                return RedirectToAction("JobList");
            }
            else
            {
                return View(new JobListViewModel(t, page.HasValue ? page.Value : 1));
            }
        }

        [Authorize(Roles = RoleNames.Company)]
        [HttpGet]
        public ActionResult EditJob(string jobToken)
        {
            return View(new EditJobViewModel(jobToken));
        }

        [Authorize(Roles = RoleNames.Company)]
        [HttpPost]
        [ValidateInput(false)]
        public JsonResult EditJob(EditJobViewModel model)
        { 
            if (model.Job.ApplyViaEmail && string.IsNullOrEmpty(model.Job.ApplyEmail))
            {
                ModelState.AddModelError("Job.ApplyEmail", "The Email field is required");
            }
            else if (!model.Job.ApplyViaEmail && string.IsNullOrEmpty(model.Job.ApplyUrl))
            {
                ModelState.AddModelError("Job.ApplyUrl", "The Url field is required");
            }
            if (ModelState.IsValid)
            {
                //update job
                try
                {
                    DataUtils.UpdateJobForEdit(model.Job, IdentityWithoutUserName.AccountID);
                    string redirectUrl = Url.Action("JobList");
                    return Json(JsonResultModelHelper.ForSuccess(redirectUrl, "Your changes are saved successfully"));
                }
                catch
                { 
                    return Json(JsonResultModelHelper.ForError("Sorry, internal error occurred. Please try it again."));
                }
            }
            else
            { 
                return Json(JsonResultModelHelper.ForError(ModelState));
            }
        }
        
        //show single job info for public
        public ActionResult Job(int jobID, string jobTitle)
        {
            return View(new JobViewModel(jobID));
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult BillingHistory()
        {
            return View(new BillingInfoViewModel());
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult SavedJobs(int? page)
        {
            return View(new CoSavedJobViewModel(page == null ? 1 : page.Value));
        }

        [Authorize(Roles = RoleNames.Company)]
        public ActionResult SavedTalent(int? page)
        {
            return View(new CoSavedTalentViewModel(page == null ? 1 : page.Value));
        }

    }
}
